#include "reportwidget.h"
#include "ui_reportwidget.h"

#include <QtGui>

ReportWidget::ReportWidget(QWidget *parent) :
	QFrame(parent),
	ui(new Ui::ReportWidget)
{
	ui->setupUi(this);
	QButtonGroup *group = new QButtonGroup(this);
	group->addButton(ui->btnSnapRight);
	group->addButton(ui->btnSnapBottom);

	ui->btnSnapRight->setChecked(true);

	ui->textEdit->installEventFilter(this);
	connect(ui->textEdit, SIGNAL(anchorClicked(QString)), this, SLOT(onAnchorClicked(QString)));
}

ReportWidget::~ReportWidget()
{
	delete ui;
}

QList<TextAnchor> ReportWidget::anchors()
{
	QList<TextAnchor> result;
	for (QTextBlock block = ui->textEdit->document()->begin(); block.isValid(); block = block.next()) {
		QTextCharFormat format = block.charFormat();
		if (format.isAnchor()) {
			TextAnchor a;
			if (decodeAnchor(format.anchorHref(), a.docHash, a.pageNumber, a.normalizedPos)) {
				result << a;
			}
		}
		for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
			QTextFragment fragment = it.fragment();
			format = fragment.charFormat();
			if (format.isAnchor()) {
				TextAnchor a;
				if (decodeAnchor(format.anchorHref(), a.docHash, a.pageNumber, a.normalizedPos)) {
					result << a;
				}
			}
		}
	}
	return result;
}

QTextEdit *ReportWidget::getTextEdit()
{
	return ui->textEdit;
}

void ReportWidget::setText(QString text)
{
	ui->textEdit->setHtml(text);
}

bool ReportWidget::insertAnchor(int pageNumber, QPointF normalizedPos)
{
	if (ui->btnInsertAnchor->isChecked()) {
		QTextCursor cursor = ui->textEdit->textCursor();
		if (cursor.anchor() == cursor.position()) {
			// no selection
			cursor.beginEditBlock();
			cursor.insertHtml(QString("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span><a href='#%1_%2_%3' name='Page %1'><img src=':/icons/flag-green-16.png' /></a><span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span>").arg(pageNumber).arg(normalizedPos.x()).arg(normalizedPos.y()));
			cursor.endEditBlock();
		} else {
			// selection
			QString text = cursor.selectedText();
			cursor.beginEditBlock();
			cursor.removeSelectedText();
			cursor.insertHtml(QString("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span><a href='#%1_%2_%3' name='Page %1'>%4<img src=':/icons/flag-green-16.png' /></a><span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span>").arg(pageNumber).arg(normalizedPos.x()).arg(normalizedPos.y()).arg(text));
			cursor.endEditBlock();
		}
		ui->btnInsertAnchor->setChecked(false);
		return true;
	}
	// we did not request any anchor
	return false;
}

bool ReportWidget::insertInterDocAnchor(QByteArray docHash, int pageNumber, QPointF normalizedPos, QString reference)
{
	if (ui->btnInsertAnchorInterDoc->isChecked()) {
		QTextCursor cursor = ui->textEdit->textCursor();
		if (cursor.anchor() == cursor.position()) {
			// no selection
			cursor.beginEditBlock();
			cursor.insertHtml(QString("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span><a href='#%4_%1_%2_%3' name='Page %1'>%5<img src=':/icons/flag-blue-16.png' /></a><span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span>").arg(pageNumber).arg(normalizedPos.x()).arg(normalizedPos.y()).arg(QString::fromAscii(docHash.toHex())).arg(reference.isEmpty() ? QString() : QString("[%1]").arg(reference)));
			cursor.endEditBlock();
		} else {
			// selection
			QString text = cursor.selectedText();
			cursor.beginEditBlock();
			cursor.removeSelectedText();
			cursor.insertHtml(QString("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span><a href='#%5_%1_%2_%3' name='Page %1'>%4 %6<img src=':/icons/flag-blue-16.png' /></a><span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span>").arg(pageNumber).arg(normalizedPos.x()).arg(normalizedPos.y()).arg(text).arg(QString::fromAscii(docHash.toHex())).arg(reference.isEmpty() ? QString() : QString("[%1]").arg(reference)));
			cursor.endEditBlock();
		}
		ui->btnInsertAnchorInterDoc->setChecked(false);
		return true;
	}
	// we did not request any anchor
	return false;
}

void ReportWidget::on_btnSnapBottom_toggled(bool checked)
{
	if (checked) {
		emit snapBottomRequested();
	}
}

void ReportWidget::on_btnSnapRight_toggled(bool checked)
{
	if (checked) {
		emit snapRightRequested();
	}
}

void ReportWidget::on_textEdit_textChanged()
{
	emit textChanged(ui->textEdit->toHtml());
}

bool ReportWidget::eventFilter(QObject *obj, QEvent *event)
{
	if (obj == ui->textEdit) {
		if (event->type() == QEvent::KeyPress) {
			QKeyEvent *e = dynamic_cast<QKeyEvent *>(event);
			if (e) {
				if (e->key() == Qt::Key_Return) {
					QTextCursor cursor = ui->textEdit->textCursor();
					if (cursor.anchor() == cursor.position()) {
						// no selection
						QString line = cursor.block().text();
						QString tag;
						if (line.startsWith("===== ") && line.endsWith(" =====")) {
							tag = "h5";
							line = line.mid(6, line.length() - 12);
						} else if (line.startsWith("==== ") && line.endsWith(" ====")) {
							tag = "h4";
							line = line.mid(5, line.length() - 10);
						} else if (line.startsWith("=== ") && line.endsWith(" ===")) {
							tag = "h3";
							line = line.mid(4, line.length() - 8);
						} else if (line.startsWith("== ") && line.endsWith(" ==")) {
							tag = "h2";
							line = line.mid(3, line.length() - 6);
						} else if (line.startsWith("= ") && line.endsWith(" =")) {
							tag = "h1";
							line = line.mid(2, line.length() - 4);
						}
						if (!tag.isEmpty()) {
							cursor.beginEditBlock();
							cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
							cursor.removeSelectedText();
							cursor.insertHtml(QString("<%1>%2</%1><br />").arg(tag).arg(line));
							cursor.endEditBlock();
							event->setAccepted(true);
							return true;
						}
					}
				}
			}
		}
	}
	bool result = QObject::eventFilter(obj, event);
	return result;
}

bool ReportWidget::decodeAnchor(QString anchor, QByteArray &docHash, int &pageNumber, QPointF &normalizedPos)
{
	if (!anchor.startsWith('#'))
		return false;
	anchor = anchor.mid(1);
	QStringList tokens = anchor.split('_', QString::SkipEmptyParts);
	if (tokens.count() == 3) {
		// in-document link
		docHash.clear();
		bool ok;
		pageNumber = tokens.takeFirst().toInt(&ok);
		if (!ok)
			return false;
		normalizedPos.rx() = tokens.takeFirst().toDouble(&ok);
		if (!ok)
			return false;
		normalizedPos.ry() = tokens.takeFirst().toDouble(&ok);
		if (!ok)
			return false;
		return true;
	} else if (tokens.count() == 4) {
		// inter-document link
		docHash = QByteArray::fromHex(tokens.takeFirst().toAscii());
		if (docHash.length() != 20) // SHA-1 size in bytes
			return false;
		bool ok;
		pageNumber = tokens.takeFirst().toInt(&ok);
		if (!ok)
			return false;
		normalizedPos.rx() = tokens.takeFirst().toDouble(&ok);
		if (!ok)
			return false;
		normalizedPos.ry() = tokens.takeFirst().toDouble(&ok);
		if (!ok)
			return false;
		return true;
	} else {
		return false;
	}
}

void ReportWidget::on_btnBold_toggled(bool checked)
{
	ui->textEdit->setFontWeight(checked ? QFont::Bold : QFont::Normal);
	ui->textEdit->setFocus();
}

void ReportWidget::on_textEdit_currentFontChanged(const QFont &f)
{
	if (ui->textEdit->textCursor().anchor() != ui->textEdit->textCursor().position()) {
		// something is selected, do not touch the buttons or we alter the format
		return;
	}
	ui->btnBold->setChecked(f.weight() == QFont::Bold);
	ui->btnItalic->setChecked(f.style() == QFont::StyleItalic);
	ui->btnUnderline->setChecked(ui->textEdit->currentCharFormat().fontUnderline());
	ui->btnStrikethrough->setChecked(ui->textEdit->currentCharFormat().fontStrikeOut());
	ui->btnMonospace->setChecked(ui->textEdit->currentCharFormat().fontStyleHint() == QFont::Courier);
	ui->btnSubscript->setChecked(ui->textEdit->currentCharFormat().verticalAlignment() == QTextCharFormat::AlignSubScript);
	ui->btnSuperscript->setChecked(ui->textEdit->currentCharFormat().verticalAlignment() == QTextCharFormat::AlignSuperScript);
}

void ReportWidget::on_btnItalic_toggled(bool checked)
{
	ui->textEdit->setFontItalic(checked);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnUnderline_toggled(bool checked)
{
	ui->textEdit->setFontUnderline(checked);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnStrikethrough_toggled(bool checked)
{
	QTextCharFormat f = ui->textEdit->currentCharFormat();
	f.setFontStrikeOut(checked);
	ui->textEdit->setCurrentCharFormat(f);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnMonospace_toggled(bool checked)
{
	QTextCharFormat f = ui->textEdit->currentCharFormat();
	f.setFontStyleHint(checked ? QFont::Courier : QFont::Helvetica);
	ui->textEdit->setCurrentCharFormat(f);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnSubscript_toggled(bool)
{
	QTextCharFormat f = ui->textEdit->currentCharFormat();
	if (ui->btnSubscript->isChecked()) {
		f.setVerticalAlignment(QTextCharFormat::AlignSubScript);
		ui->btnSuperscript->setChecked(false);
	} else if (ui->btnSuperscript->isChecked()) {
		f.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
		ui->btnSubscript->setChecked(false);
	} else {
		f.setVerticalAlignment(QTextCharFormat::AlignNormal);
	}
	ui->textEdit->setCurrentCharFormat(f);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnSuperscript_toggled(bool)
{
	QTextCharFormat f = ui->textEdit->currentCharFormat();
	if (ui->btnSuperscript->isChecked()) {
		f.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
		ui->btnSubscript->setChecked(false);
	} else if (ui->btnSubscript->isChecked()) {
		f.setVerticalAlignment(QTextCharFormat::AlignSubScript);
		ui->btnSuperscript->setChecked(false);
	} else {
		f.setVerticalAlignment(QTextCharFormat::AlignNormal);
	}
	ui->textEdit->setCurrentCharFormat(f);
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnPickTextColor_clicked()
{
	QColorDialog dialog;
	dialog.setCurrentColor(ui->textEdit->textColor());
	dialog.setWindowTitle("Select text color");

	if (dialog.exec() != QDialog::Accepted)
		return;
	ui->textEdit->setTextColor(dialog.currentColor());
	ui->textEdit->setFocus();
}

void ReportWidget::on_btnClearFormatting_clicked()
{
	QTextCursor cursor = ui->textEdit->textCursor();
	if (cursor.anchor() == cursor.position()) {
		// no selection
		cursor.beginEditBlock();
		cursor.insertHtml("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>&nbsp;</span>");
		cursor.endEditBlock();
	} else {
		// selection
		QString text = cursor.selectedText();
		cursor.beginEditBlock();
		cursor.removeSelectedText();
		cursor.insertHtml(QString("<span style='margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;'>%1</span>").arg(text));
		cursor.endEditBlock();
	}
}

void ReportWidget::onAnchorClicked(QString anchor)
{
	QByteArray docHash;
	int pageNumber;
	QPointF normalizedPos;
	if (!decodeAnchor(anchor, docHash, pageNumber, normalizedPos))
		return;
	if (docHash.isEmpty()) {
		emit navigateRequested(pageNumber, normalizedPos);
	} else {
		emit navigateRequested(docHash, pageNumber, normalizedPos);
	}
}
